package org.datascooter.bundle.attribute;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import org.datascooter.utils.DBType;
import org.datascooter.utils.LangUtils;

/**
 * This persistable attribute may be restored into instance variable via method access
 * 
 * @author nemo
 * 
 */
public class PersistMethodAttribute extends PersistAttribute {

	protected transient Method getter;
	protected transient Method setter;

	public PersistMethodAttribute(String name, String column, DBType type, int scale, int precision, boolean insertable, boolean updatable, boolean nullable) {
		super(name, type, column, scale, precision, nullable, insertable, updatable);
	}

	@SuppressWarnings("unchecked")
	@Override
	public PersistMethodAttribute copy() {
		return new PersistMethodAttribute(name, getColumn(), getType(), getScale(), getPrecision(), insertable, updatable, isNullable());
	}

	@SuppressWarnings("unchecked")
	@Override
	public PersistMethodAttribute copyMod(DBType dbType) {
		return new PersistMethodAttribute(name, getColumn(), dbType, scale, precision, insertable, updatable, isNullable());
	}

	@Override
	public String getActorName() {
		return getter.getName();
	}

	@Override
	public void explore(Class<?> clazz) throws SecurityException, NoSuchMethodException {
		if (name.startsWith(GET)) {
			getter = clazz.getMethod(name);
		} else {
			try {
				getter = clazz.getMethod(GET + LangUtils.capitalize(name));
			} catch (NoSuchMethodException e) {
				if (type.equals(DBType.BOOLEAN)) {
					getter = clazz.getMethod(IS + LangUtils.capitalize(name));
				} else {
					throw e;
				}
			}
		}
		setGetClass(getter.getReturnType());
		if (name.startsWith(SET)) {
			try {
				setter = clazz.getMethod(name, new Class[] {
					getClass
				});
			} catch (NoSuchMethodException e) {
				setter = clazz.getMethod(name, new Class[] {
					String.class
				});
			}
		} else {
			try {
				setter = clazz.getMethod(SET + LangUtils.capitalize(name), new Class[] {
					getClass
				});
			} catch (NoSuchMethodException e) {
				setter = clazz.getMethod(SET + LangUtils.capitalize(name), new Class[] {
					String.class
				});
			}
		}
		setSetClass(setter.getParameterTypes()[0]);
	}

	@Override
	protected Object invoke(Object obj) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
		return getter.invoke(obj);
	}

	@Override
	protected void revoke(Object obj, Object param) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
		setter.invoke(obj, param);
	}
}
